package com.example.controller;

import com.example.model.Person;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/persons")
@RequiredArgsConstructor
public class PersonController {

    private final RestHighLevelClient client;
    private final ObjectMapper objectMapper;
    private static final String INDEX_NAME = "my_index";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @GetMapping
    public ResponseEntity<List<Person>> getAllPersons() {
        try {
            SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchAllQuery());
            searchSourceBuilder.size(100);
            searchRequest.source(searchSourceBuilder);

            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            
            List<Person> persons = new ArrayList<>();
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                Person person = objectMapper.readValue(hit.getSourceAsString(), Person.class);
                persons.add(person);
            }
            
            return ResponseEntity.ok(persons);
        } catch (IOException e) {
            log.error("Error searching for persons", e);
            return ResponseEntity.internalServerError().build();
        }
    }
    
    @GetMapping("/search")
    public ResponseEntity<List<Person>> searchPersons(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) Integer minAge,
            @RequestParam(required = false) Integer maxAge) {
        
        try {
            SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            
            // 构建查询
            if (name != null || minAge != null || maxAge != null) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                
                if (name != null && !name.isEmpty()) {
                    boolQueryBuilder.must(QueryBuilders.matchQuery("name", name));
                }
                
                if (minAge != null || maxAge != null) {
                    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");
                    if (minAge != null) {
                        rangeQueryBuilder.gte(minAge);
                    }
                    if (maxAge != null) {
                        rangeQueryBuilder.lte(maxAge);
                    }
                    boolQueryBuilder.must(rangeQueryBuilder);
                }
                
                searchSourceBuilder.query(boolQueryBuilder);
            } else {
                searchSourceBuilder.query(QueryBuilders.matchAllQuery());
            }
            
            searchSourceBuilder.size(100);
            searchRequest.source(searchSourceBuilder);
            
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            
            List<Person> persons = new ArrayList<>();
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                Person person = objectMapper.readValue(hit.getSourceAsString(), Person.class);
                persons.add(person);
            }
            
            return ResponseEntity.ok(persons);
        } catch (IOException e) {
            log.error("Error searching for persons", e);
            return ResponseEntity.internalServerError().build();
        }
    }
    
    @GetMapping("/add")
    public ResponseEntity<Map<String, Object>> addPerson(
            @RequestParam String name,
            @RequestParam int age,
            @RequestParam(defaultValue = "") String createdAt) {
        
        try {
            // 如果没有提供创建日期，使用当前日期
            LocalDate date = createdAt.isEmpty() ? 
                    LocalDate.now() : 
                    LocalDate.parse(createdAt, DATE_FORMATTER);
            
            Person person = new Person(name, age, date);
            
            IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
                    .source(objectMapper.writeValueAsString(person), XContentType.JSON);
            
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
            
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("id", response.getId());
            result.put("message", "Person added successfully");
            result.put("person", person);
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("Error adding person via GET", e);
            
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "Failed to add person: " + e.getMessage());
            
            return ResponseEntity.ok(result);
        }
    }

    @PostMapping
    public ResponseEntity<Map<String, Object>> createPerson(@RequestBody Person person) {
        try {
            IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
                    .source(objectMapper.writeValueAsString(person), XContentType.JSON);
            
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
            
            Map<String, Object> result = new HashMap<>();
            result.put("id", response.getId());
            result.put("result", response.getResult().name());
            result.put("person", person);
            
            return ResponseEntity.ok(result);
        } catch (IOException e) {
            log.error("Error creating person", e);
            return ResponseEntity.internalServerError().build();
        }
    }
    
    @PostMapping("/bulk")
    public ResponseEntity<Map<String, Object>> createPersonsBulk(@RequestBody List<Person> persons) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            
            for (Person person : persons) {
                IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
                        .source(objectMapper.writeValueAsString(person), XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
            
            BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            
            boolean hasErrors = response.hasFailures();
            
            if (hasErrors) {
                return ResponseEntity.ok(Map.of(
                        "success", false,
                        "error", "Some documents failed to index: " + response.buildFailureMessage(),
                        "count", persons.size()
                ));
            } else {
                return ResponseEntity.ok(Map.of(
                        "success", true,
                        "count", persons.size(),
                        "took", response.getTook().getMillis()
                ));
            }
        } catch (IOException e) {
            log.error("Error bulk creating persons", e);
            return ResponseEntity.internalServerError().build();
        }
    }
} 